
#include "netsend.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <time.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <pthread.h>

static unsigned char *buffer = NULL;
static uint32_t total_size = 0;
static uint32_t total_id = 0;

static uint32_t calc_checksum(void *data, uint32_t size)
{
	uint32_t i = 0, sum = 0xFFFFFFFF;
	for(i = 0; size > i; i += 4)
	{
		sum += *(unsigned int *)((unsigned char *)data + i);
	}
	return sum;
}

static int file_block_cmd_parse(int socket)
{
	return -1;
}

static int file_block_send_block(int socket, uint32_t id)
{
	FILE *fp = NULL;
	struct file_block *block = NULL;
	struct net_package package;
	
	uint32_t offset = FILE_DATA * id;

	if(NULL != fp)
	{
		memset(&package, 0, PACKAGE_TOTAL);

		block = (struct file_block *)package.data;

		block->block_type = 1;
		block->block_id = id;
		block->block_total = total_id;
		block->valid_len = FILE_DATA < total_size - offset ? FILE_DATA : total_size - offset;

		package.type = 0;
		package.valid_len = FILE_INFO + block->valid_len;
		package.checksum = calc_checksum(package.data, package.valid_len);

		write(socket, &package, package.valid_len + PACKAGE_INFO);

		return 0;
	}
	return -1;
}

static int file_block_parse(int socket, struct file_block *file, uint32_t len)
{
	int ret = 0;

	switch(file->block_type)
	{
		case 0:
			ret = -1;
			break;
		case 1:
			ret = -1;
			break;
		case 2:
			ret = file_block_send_block(socket, *(uint32_t *)file->data);
			break;
		case 3:
			ret = file_block_cmd_parse(socket);
			break;
		default:
			ret = -1;
			break;
	}
	return ret;
}

static int net_package_checksum(struct net_package *package)
{
	return package->checksum == calc_checksum(package->data, package->valid_len) ? 0 : -1;
}

static int net_package_parse(int socket, struct net_package *package)
{
	int ret = 0;

	if(0 != net_package_checksum(package))
	{
		printf("%s: checksum failed\n", __func__);
		return -1;
	}

	switch(package->type)
	{
		case 0:
			ret = file_block_parse(socket, (struct file_block *)package->data, package->valid_len);
			break;
		case 1:
			break;
		default:
			break;
	}
	return ret;
}

int send_to_server(char *ip, int port, bitmap_class *bmp)
{
	int ret = 0;

	int sockfd = 0;
	struct sockaddr_in remote_addr;
	
	uint32_t filesize = 0;

	struct net_package package;
	struct file_block *block = NULL;
	
	if(PACKAGE_TOTAL != sizeof(struct net_package))
	{
		return -1;
	}

	sockfd = socket(AF_INET, SOCK_STREAM, 0);

	memset(&remote_addr, 0, sizeof(remote_addr));

	remote_addr.sin_family = AF_INET;
	remote_addr.sin_port = htons(port);
	remote_addr.sin_addr.s_addr = inet_addr(ip);

	if(0 == connect(sockfd, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)))
	{
		bmp->memdup(bmp, &buffer, &filesize);

		if(0 < filesize)
		{
			memset(&package, 0, PACKAGE_TOTAL);

			total_size = (uint32_t)filesize;
			total_id = total_size / FILE_DATA + 1;

			block = (struct file_block *)package.data;

			block->block_type = 0;
			block->block_id = 0;
			block->block_total = total_id;
			block->valid_len = 0;

			package.type = 0;
			package.valid_len = FILE_INFO + block->valid_len;
			package.checksum = calc_checksum(package.data, package.valid_len);
		
			write(sockfd, &package, package.valid_len + PACKAGE_INFO);
			
			while(1)
			{
				memset(&package, 0, PACKAGE_TOTAL);

				ret = read(sockfd, &package, PACKAGE_TOTAL);

				if(0 >= ret)
				{
					printf("%s: read failed!!!\n", __func__);
					ret = -1;
					break;
				}
				else
				{
					ret = net_package_parse(sockfd, &package);
					if(0 != ret)
					{
						ret = -1;
						break;
					}
				}
			}
		}
		else
		{
			return -1;
		}

		bmp->memfree(bmp, &buffer);
	}
	else
	{
		printf("connect failed\n");
		ret = -1;
	}

	close(sockfd);
	return ret;
}